struct Topic {
  pair pos;
  pair alignment;
  object content;
  Topic[] children;
  real xheight;

  Topic copy(bool copyChilds=true) {
    Topic node = new Topic;
    node.content=content;
    node.pos=pos;
    node.children=children;
    node.xheight=xheight;
    if (copyChilds) node.children=copy(children);
    return node;
  }

  //without subtrees
  real getContentWidth() {
    return size(content.f).x;
  }
  
  Topic transform(transform t, Topic N)
  {
    Topic tN=N.copy();
    tN.pos=t*N.pos;
    for (int i=0; i < N.children.length; ++i) {
      tN.children[i]=transform(t,N.children[i]);
    }
    return tN;
  }

  void operator init(object content, pair pos=(0,0) ... Topic children[]) {
    this.content=content;
    this.children=children;
    
    //to place lines below content
    //TODO: depend on pen (assuming a pen is a node attribute)
    frame xdim;
    Label("x").out(xdim);
    this.xheight=ypart(max(xdim)-min(xdim));
  }

  real getHeight() {
    return size(this.content.f).y;
  }

  path subtopicPath(pair topic, pair subtopic) {
    return (topic).. controls ((subtopic.x+topic.x)/2,topic.y) and ((subtopic.x+topic.x)/2,subtopic.y) ..(subtopic);
  }

  void out(picture dest=currentpicture) {
    add(dest, align(this.content,this.alignment), pos);

    draw(dest, shift(0,-xheight)*(pos -- shift(alignment * getContentWidth())*pos));

    //DO NOT DELETE following LINE, ITS USEFUL
    //draw(dest, shift(pos)*box(min(content),max(content)));

    for (int i=0; i < children.length; ++i) {
      children[i].out(dest);
      draw(dest, subtopicPath(shift(0,-xheight)*shift(alignment * getContentWidth())*pos, shift(0,-children[i].xheight)*children[i].pos));
    }
  }
}

// shift should work and operator needs to be improved
Topic operator * (transform t, Topic N)
{
  return N.transform(t,N);
}

Topic Topic(string content, pair pos=(0,0) ... Topic children[]) {
  return Topic(Label(baseline(content),basealign), pos ... children);
}
